//
//  APIBaseManager.m
//  BaoZhangWang
//
//  Created by 叶越悦 on 15/10/14.
//  Copyright © 2015年 BaoliNetworkTechnology. All rights reserved.
//

#import "APIBaseManager.h"
#import "APIBaseService.h"
#import "APICache.h"
#import "HTTPLogger.h"
#import "APIBaseManager+Interceptor.h"
#import "APIBaseManager+validator.h"
#import "AFNetworking.h"
#import "URLResponseInternal.h"

@interface APIBaseManager ()

@property (nonatomic, assign, readwrite) APIManagerStatus status;
@property (nonatomic, strong, readwrite) URLResponse *response;
@property (nonatomic, strong, readwrite) id responseObject;
@property (nonatomic, strong) NSMutableSet *igonerCallBackIDSet;
@property (nonatomic, strong, readwrite) NSError *error;
@property (nonatomic, strong) NSMutableArray *requestIDList;
@property (nonatomic, readwrite) NSInteger requestIdentifier; /**< 请求ID */

@end

static NSString *kMessageNoNetwork = @"网络未连接，请检查网络是否连接！";
static NSString *kMessageNoCacheData = @"无缓存数据";

@implementation APIBaseManager

+ (instancetype)managerWithParamSource:(id <APIManagerParamSourceDelegate>)paramSource
                              delegate:(id <APIManagerApiCallBackDelegate>)delegate {
    APIBaseManager *manager = [[self alloc] init];
    manager.paramSource = paramSource;
    manager.delegate = delegate;
    return manager;
}

+ (instancetype)managerWithDelegate:(id <APIManagerApiCallBackDelegate>)delegate {
    APIBaseManager *manager = [[self alloc] init];
    manager.delegate = delegate;
    return manager;
}

- (instancetype)init {
    if (self = [super init]) {
        if (![self conformsToProtocol:@protocol(APIManager)]) {
            NSAssert(NO, @"子类必须实现 APIManager 协议");
        }
        _requestPolicy = kAPIRequestPolicyReturnCacheDataElseReloadRemoteData;
    }
    return self;
}

- (void)dealloc {
    [self cancelAllRequestsAndIgonerCallBack];
#ifdef DEBUG
    NSLog(@"dealloc %@", NSStringFromClass(self.class));
#endif
}

#pragma mark - 公开方法

- (BOOL)isReachable {
    return [AFNetworkReachabilityManager sharedManager].isReachable;
}

#pragma mark end -

#pragma mark - 发起请求

- (NSInteger)loadDataDidComplete:(APICompletionBlock)complete {
    id params = nil;
    if (self.paramSource && [self.paramSource respondsToSelector:@selector(paramsForApi:)]) {
        params = [self.paramSource paramsForApi:self];
    } else {
        params = self.requestParam;
    }
    return [self loadDataWithParam:params complete:complete];
}

- (NSInteger)loadDataWithParam:(id)params complete:(APICompletionBlock)complete {
    self.completionBlock = complete;
    return [self loadDataWithParam:params];
}

- (NSInteger)loadData {
    id params = nil;
    if (self.paramSource && [self.paramSource respondsToSelector:@selector(paramsForApi:)]) {
        params = [self.paramSource paramsForApi:self];
    } else {
        params = self.requestParam;
    }
    return [self loadDataWithParam:params];
}

- (NSInteger)loadDataWithParam:(id)params {
    self.responseObject = nil;
    self.reformResponseObject = nil;
    self.error = nil;
    self.status = APIManagerStatusDefault;
    self.requestIdentifier = 0;
    id apiParams = [self base_APIReformParams:params];
    self.requestParam = apiParams;
    //拦截器，调用API前还是能取消当前请求
    if (![self base_shouldCallAPIWithParams:apiParams]) {
        return self.requestIdentifier;
    }
    
    //校验器，校验请求参数是否正确
    NSError *error = [self base_validateParameterData:apiParams];
    if (error) {
        self.error = error;
        self.status = APIManagerStatusParamsError;
        [self failedOnCallingWithResponse:nil];
        return self.requestIdentifier;
    }
    
    APIBaseManager <APIManager> *manager = (id <APIManager>) self;
    //检测缓存
    if (manager.APIShouldCache &&
        (manager.requestPolicy == kAPIRequestPolicyReturnCacheDataElseReloadRemoteData ||
         manager.requestPolicy == kAPIRequestPolicyReturnCacheDataThenReloadRemoteData)) {
            id obj = [self.cache cacheObjectForManager:manager];
            if (obj) {
                URLResponse *response = [URLResponse new];
                response.responseObject = [obj mutableCopy];
                response.requestParams = apiParams;
                self.status = APIManagerStatusSuccessFromCache;
                self.reformResponseObject = response.responseObject;
                [self callDelegateSucessWithResponse:response];
                //有缓存数据不在执行网络请求
                if (self.requestPolicy == kAPIRequestPolicyReturnCacheDataElseReloadRemoteData) {
                    return self.requestIdentifier;
                }
            }
        }
    
    //进行网络请求
    if (self.isReachable) {
        self.status = APIManagerStatusLoading;
        __weak __typeof(self) weakSelf = self;
        self.requestIdentifier = [[APIBaseService service] callAPIManager:manager complete:^(URLResponse *response) {
            __strong __typeof(weakSelf) self = weakSelf;
            if (!self) {
                return;
            }
            [self apiCallBack:response];
        }];
        @synchronized (self) {
            [self.requestIDList addObject:@(self.requestIdentifier)];
        }
        //只有实际发起请求才会走这个
        [self base_afterCallAPIWithParams:apiParams];
    } else {
        NSError *error = [NSError errorWithDomain:kMessageNoNetwork code:APIManagerStatusNoNetwork userInfo:@{NSLocalizedDescriptionKey: kMessageNoNetwork}];
        self.status = APIManagerStatusNoNetwork;
        self.error = error;
        URLResponse *response = [URLResponse new];
        response.error = error;
        [self failedOnCallingWithResponse:response];
    }
    return self.requestIdentifier;
}

#pragma mark end -

#pragma mark - 网络请求返回

- (void)apiCallBack:(URLResponse *)response {
    if ([self.requestIDList.copy containsObject:@(response.requestIdentifier)]) {
        [self.requestIDList removeObject:@(response.requestIdentifier)];
    }
    self.response = response;
#if DEBUG
    [HTTPLogger logWithResponer:response];
#endif
    self.responseObject = response.responseObject;
    if (response.status == URLResponseStatusSuccess) {
        self.reformResponseObject = [(id <APIManager>) self APIReformResponseObject:response.responseObject];
        //校验返回的数据，直接使用转换后的数据比较方便
        NSError *error = [self base_validateCallBackData:self.reformResponseObject];
        if (error == nil) {
            self.status = APIManagerStatusSuccess;
            dispatch_async(dispatch_get_main_queue(), ^{
                [self callDelegateSucessWithResponse:response];
            });
        } else {
            self.status = APIManagerStatusNoContent;
            self.error = error;
            response.error = error;
            dispatch_async(dispatch_get_main_queue(), ^{
                [self failedOnCallingWithResponse:response];
            });
        }
    } else {
        self.status = APIManagerStatusHttpError;
        self.error = response.error;
        dispatch_async(dispatch_get_main_queue(), ^{
            [self failedOnCallingWithResponse:response];
        });
    }
}

- (void)failedOnCallingWithResponse:(URLResponse *)response {
    /**kAPIRequestPolicyReloadRemoteDataElseReturnCacheData  请求失败尝试读取缓存 */
    APIBaseManager <APIManager> *manager = (id <APIManager>) self;
    if (self.status != APIManagerStatusParamsError &&
        self.requestPolicy == kAPIRequestPolicyReloadRemoteDataElseReturnCacheData && manager.APIShouldCache) {
        id obj = [self.cache cacheObjectForManager:manager];
        if (obj) {
            if (!response) {
                response = [URLResponse new];
            }
            response.responseObject = [obj mutableCopy];
            response.error = nil;
            response.requestParams = self.requestParam;
            self.status = APIManagerStatusSuccessFromCache;
            self.responseObject = response.responseObject;
            self.reformResponseObject = response.responseObject;
            [self callDelegateSucessWithResponse:response];
            return;
        }
    }
    [self callDelegateFailureWithResponse:response];
}

#pragma mark - delegate或者block处理

- (void)callDelegateSucessWithResponse:(URLResponse *)response {
    if (self.status == APIManagerStatusSuccess) {
        [self cacheReformResponseObject];
    }
    if (self.igonerCallBackIDSet.count) {
        if ([self.igonerCallBackIDSet.copy containsObject:@(response.requestIdentifier)]) {
            [self.igonerCallBackIDSet removeObject:@(response.requestIdentifier)];
            return;
        }
    }
    if (![self base_beforePerformCallBackWithReponse:response] ||
        ![self base_beforePerformSuccessWithResponse:response]) {
        return;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(managerCallAPIDidSuccess:)]) {
        [self.delegate managerCallAPIDidSuccess:self];
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(managerCallAPIDidComplete:success:)]) {
        [self.delegate managerCallAPIDidComplete:self success:YES];
    }
    if (self.completionBlock) {
        self.completionBlock(YES, self);
    }
    [self base_afterPerformCallBackWithResponse:response];
    [self base_afterPerformSuccessWithResponse:response];
}

- (void)callDelegateFailureWithResponse:(URLResponse *)response {
    if (self.igonerCallBackIDSet.count) {
        if ([self.igonerCallBackIDSet.copy containsObject:@(response.requestIdentifier)]) {
            [self.igonerCallBackIDSet removeObject:@(response.requestIdentifier)];
            return;
        }
    }
    if (![self base_beforePerformCallBackWithReponse:response] ||
        ![self base_beforePerformFailWithResponse:response]) {
        return;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(managerCallAPIDidFailed:)]) {
        [self.delegate managerCallAPIDidFailed:self];
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(managerCallAPIDidComplete:success:)]) {
        [self.delegate managerCallAPIDidComplete:self success:NO];
    }
    if (self.completionBlock) {
        self.completionBlock(NO, self);
    }
    [self base_afterPerformCallBackWithResponse:response];
    [self base_afterPerformFailWithResponse:response];
}

#pragma mark end -

#pragma mark - 本地缓存

- (void)cacheReformResponseObject {
    if ([(id <APIManager>) self APIShouldCache]) {
        id reformObject = [self.reformResponseObject copy];
        [self.cache storeObject:reformObject withManager:(id <APIManager>) self];
    }
}

#pragma mark end -

#pragma mark - 取消网络请求

- (void)cancelAllRequests {
    @synchronized (self) {
        [[APIBaseService service] cancelRequestWithRequestIDList:self.requestIDList];
        [self.requestIDList removeAllObjects];
    }
}

- (void)cancelAllRequestsAndIgonerCallBack {
    @synchronized (self) {
        if (self.requestIDList.count) {
            [self.igonerCallBackIDSet addObjectsFromArray:self.requestIDList];
            [[APIBaseService service] cancelRequestWithRequestIDList:self.requestIDList];
            [self.requestIDList removeAllObjects];
        }
    }
}

- (void)cancelRequestWithRequestID:(NSInteger)requestID {
    [[APIBaseService service] cancelRequestWithRequestID:@(requestID)];
    [self.requestIDList removeObject:@(requestID)];
}

#pragma mark end -

#pragma mark -  get, set

- (NSMutableSet *)igonerCallBackIDSet {
    if (!_igonerCallBackIDSet) {
        _igonerCallBackIDSet = [NSMutableSet set];
    }
    return _igonerCallBackIDSet;
}

- (id)cache {
    if (!_cache) {
        _cache = [APICache share];
    }
    return _cache;
}

- (NSMutableArray *)requestIDList {
    if (!_requestIDList) {
        _requestIDList = [NSMutableArray array];
    }
    return _requestIDList;
}

@end
